<script>
  import { onMount, onDestroy } from 'svelte';
  import { toast } from '../stores/toast';
  import {
    IconSearch,
    IconChevronLeft,
    IconChevronRight,
    IconChevronsLeft,
    IconChevronsRight,
    IconSortAsc,
    IconSortDesc,
    IconLoader,
  } from '../utils/icons';

  // ===========================
  // Props (exported)
  // ===========================

  /** API endpoint for fetching data */
  export let endpoint = '';

  /** Column definitions */
  export let columns = [];

  /** Page size (items per page) */
  export let pageSize = 20;

  /** Search placeholder text */
  export let searchPlaceholder = 'Search...';

  /** Enable search */
  export let searchable = true;

  /** Enable row selection */
  export let selectable = false;

  /** Batch actions (requires selectable=true) */
  export let batchActions = [];

  /** Row actions (edit, delete, etc.) */
  export let rowActions = [];

  /** Authentication token */
  export let authToken = '';

  /** Static data (alternative to endpoint) */
  export let data = null;

  /** Custom row key field (default: 'id') */
  export let rowKey = 'id';

  /** Empty state message */
  export let emptyMessage = 'No data available';

  // ===========================
  // Internal State
  // ===========================

  let items = [];
  let total = 0;
  let currentPage = 1;
  let loading = false;
  let error = '';
  let searchQuery = '';
  let sortField = '';
  let sortOrder = 'asc';
  let selectedRows = new Set();
  let abortController = null;
  let searchTimeout = null;

  // ===========================
  // Computed Values
  // ===========================

  $: totalPages = Math.ceil(total / pageSize);
  $: startItem = (currentPage - 1) * pageSize + 1;
  $: endItem = Math.min(currentPage * pageSize, total);
  $: allSelected = items.length > 0 && selectedRows.size === items.length;
  $: someSelected = selectedRows.size > 0 && selectedRows.size < items.length;
  $: hasSelection = selectedRows.size > 0;

  // ===========================
  // Data Fetching
  // ===========================

  async function fetchData() {
    // If static data provided, use it
    if (data) {
      items = data.items || data;
      total = data.total || items.length;
      return;
    }

    if (!endpoint) {
      error = 'No endpoint or data provided';
      return;
    }

    // Abort previous request
    if (abortController) {
      abortController.abort();
    }

    abortController = new AbortController();
    loading = true;
    error = '';

    try {
      const params = new URLSearchParams({
        skip: String((currentPage - 1) * pageSize),
        limit: String(pageSize),
      });

      if (searchQuery) {
        params.append('search', searchQuery);
      }

      if (sortField) {
        params.append('sort_by', sortField);
        params.append('sort_order', sortOrder);
      }

      const headers = {
        'Content-Type': 'application/json',
      };

      if (authToken) {
        headers['Authorization'] = `Bearer ${authToken}`;
      }

      const response = await fetch(`${endpoint}?${params}`, {
        signal: abortController.signal,
        headers,
      });

      if (!response.ok) {
        throw new Error(`HTTP ${response.status}: ${response.statusText}`);
      }

      const result = await response.json();

      items = result.items || [];
      total = result.total || 0;
    } catch (err) {
      if (err.name !== 'AbortError') {
        error = err.message;
        toast.error(`Failed to load data: ${err.message}`);
      }
    } finally {
      loading = false;
      abortController = null;
    }
  }

  // ===========================
  // Event Handlers
  // ===========================

  function handleSearch(event) {
    searchQuery = event.target.value;

    // Debounce search
    if (searchTimeout) {
      clearTimeout(searchTimeout);
    }

    searchTimeout = setTimeout(() => {
      currentPage = 1;
      selectedRows.clear();
      fetchData();
    }, 300);
  }

  function handleSort(column) {
    if (!column.sortable) return;

    if (sortField === column.field) {
      sortOrder = sortOrder === 'asc' ? 'desc' : 'asc';
    } else {
      sortField = column.field;
      sortOrder = 'asc';
    }

    currentPage = 1;
    selectedRows.clear();
    fetchData();
  }

  function handlePageChange(page) {
    if (page < 1 || page > totalPages) return;
    currentPage = page;
    fetchData();
  }

  function handleSelectAll() {
    if (allSelected) {
      selectedRows.clear();
    } else {
      items.forEach((item) => selectedRows.add(item[rowKey]));
    }
    selectedRows = selectedRows; // Trigger reactivity
  }

  function handleSelectRow(itemId) {
    if (selectedRows.has(itemId)) {
      selectedRows.delete(itemId);
    } else {
      selectedRows.add(itemId);
    }
    selectedRows = selectedRows; // Trigger reactivity
  }

  async function handleBatchAction(action) {
    if (!hasSelection) return;

    const selectedIds = Array.from(selectedRows);

    try {
      await action.handler(selectedIds);
      selectedRows.clear();
      fetchData();
    } catch (err) {
      toast.error(`Batch action failed: ${err.message}`);
    }
  }

  async function handleRowAction(action, item) {
    try {
      await action.handler(item);
      fetchData();
    } catch (err) {
      toast.error(`Action failed: ${err.message}`);
    }
  }

  function renderCell(column, item) {
    const value = item[column.field];

    if (column.render && typeof column.render === 'function') {
      return column.render(value, item);
    }

    return value ?? '-';
  }

  // ===========================
  // Lifecycle
  // ===========================

  onMount(() => {
    fetchData();
  });

  onDestroy(() => {
    if (abortController) {
      abortController.abort();
    }
    if (searchTimeout) {
      clearTimeout(searchTimeout);
    }
  });
</script>

<div class="data-table">
  <!-- Toolbar -->
  <div class="table-toolbar">
    <div class="toolbar-left">
      {#if searchable}
        <div class="search-box">
          <IconSearch size={16} />
          <input
            type="text"
            placeholder={searchPlaceholder}
            value={searchQuery}
            on:input={handleSearch}
          />
        </div>
      {/if}

      {#if hasSelection && batchActions.length > 0}
        <div class="batch-actions">
          <span class="selected-count">{selectedRows.size} selected</span>
          {#each batchActions as action}
            <button
              class="btn btn-sm btn-{action.variant || 'secondary'}"
              on:click={() => handleBatchAction(action)}
            >
              {action.label}
            </button>
          {/each}
        </div>
      {/if}
    </div>

    <div class="toolbar-right">
      <slot name="toolbar" />
    </div>
  </div>

  <!-- Table -->
  <div class="table-container">
    {#if loading}
      <div class="table-loading">
        <IconLoader size={24} class="spin" />
        <p>Loading...</p>
      </div>
    {:else if error}
      <div class="table-error">
        <p>Error: {error}</p>
        <button class="btn btn-sm" on:click={fetchData}>Retry</button>
      </div>
    {:else if items.length === 0}
      <div class="table-empty">
        <p>{emptyMessage}</p>
      </div>
    {:else}
      <table>
        <thead>
          <tr>
            {#if selectable}
              <th class="col-checkbox">
                <input
                  type="checkbox"
                  checked={allSelected}
                  indeterminate={someSelected}
                  on:change={handleSelectAll}
                />
              </th>
            {/if}

            {#each columns as column}
              <th
                class:sortable={column.sortable}
                on:click={() => handleSort(column)}
              >
                <div class="th-content">
                  <span>{column.label}</span>
                  {#if column.sortable && sortField === column.field}
                    {#if sortOrder === 'asc'}
                      <IconSortAsc size={14} />
                    {:else}
                      <IconSortDesc size={14} />
                    {/if}
                  {/if}
                </div>
              </th>
            {/each}

            {#if rowActions.length > 0}
              <th class="col-actions">Actions</th>
            {/if}
          </tr>
        </thead>

        <tbody>
          {#each items as item (item[rowKey])}
            <tr>
              {#if selectable}
                <td class="col-checkbox">
                  <input
                    type="checkbox"
                    checked={selectedRows.has(item[rowKey])}
                    on:change={() => handleSelectRow(item[rowKey])}
                  />
                </td>
              {/if}

              {#each columns as column}
                <td>
                  {@html renderCell(column, item)}
                </td>
              {/each}

              {#if rowActions.length > 0}
                <td class="col-actions">
                  <div class="action-buttons">
                    {#each rowActions as action}
                      <button
                        class="btn-icon btn-{action.variant || 'secondary'}"
                        title={action.label}
                        on:click={() => handleRowAction(action, item)}
                      >
                        {#if action.icon}
                          <svelte:component this={action.icon} size={16} />
                        {:else}
                          {action.label}
                        {/if}
                      </button>
                    {/each}
                  </div>
                </td>
              {/if}
            </tr>
          {/each}
        </tbody>
      </table>
    {/if}
  </div>

  <!-- Pagination -->
  {#if totalPages > 1}
    <div class="table-pagination">
      <div class="pagination-info">
        Showing {startItem} to {endItem} of {total} items
      </div>

      <div class="pagination-controls">
        <button
          class="btn-icon"
          disabled={currentPage === 1}
          on:click={() => handlePageChange(1)}
          title="First page"
        >
          <IconChevronsLeft size={16} />
        </button>

        <button
          class="btn-icon"
          disabled={currentPage === 1}
          on:click={() => handlePageChange(currentPage - 1)}
          title="Previous page"
        >
          <IconChevronLeft size={16} />
        </button>

        <span class="page-indicator">
          Page {currentPage} of {totalPages}
        </span>

        <button
          class="btn-icon"
          disabled={currentPage === totalPages}
          on:click={() => handlePageChange(currentPage + 1)}
          title="Next page"
        >
          <IconChevronRight size={16} />
        </button>

        <button
          class="btn-icon"
          disabled={currentPage === totalPages}
          on:click={() => handlePageChange(totalPages)}
          title="Last page"
        >
          <IconChevronsRight size={16} />
        </button>
      </div>
    </div>
  {/if}
</div>

<style>
  .data-table {
    background: white;
    border-radius: 8px;
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
    overflow: hidden;
  }

  /* Toolbar */
  .table-toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 1rem;
    border-bottom: 1px solid #e5e7eb;
    gap: 1rem;
    flex-wrap: wrap;
  }

  .toolbar-left,
  .toolbar-right {
    display: flex;
    align-items: center;
    gap: 0.75rem;
  }

  .search-box {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.75rem;
    border: 1px solid #d1d5db;
    border-radius: 4px;
    background: white;
    min-width: 250px;
  }

  .search-box :global(svg) {
    color: #9ca3af;
    flex-shrink: 0;
  }

  .search-box input {
    border: none;
    outline: none;
    flex: 1;
    font-size: 0.875rem;
  }

  .batch-actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
  }

  .selected-count {
    font-size: 0.875rem;
    color: #6b7280;
    font-weight: 500;
  }

  /* Table */
  .table-container {
    overflow-x: auto;
    min-height: 200px;
  }

  table {
    width: 100%;
    border-collapse: collapse;
  }

  thead {
    background: #f9fafb;
    border-bottom: 2px solid #e5e7eb;
  }

  th {
    padding: 0.75rem 1rem;
    text-align: left;
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    color: #6b7280;
    white-space: nowrap;
  }

  th.sortable {
    cursor: pointer;
    user-select: none;
  }

  th.sortable:hover {
    background: #f3f4f6;
  }

  .th-content {
    display: flex;
    align-items: center;
    gap: 0.5rem;
  }

  .th-content :global(svg) {
    color: #3b82f6;
  }

  tbody tr {
    border-bottom: 1px solid #e5e7eb;
  }

  tbody tr:hover {
    background: #f9fafb;
  }

  td {
    padding: 0.75rem 1rem;
    font-size: 0.875rem;
    color: #374151;
  }

  .col-checkbox {
    width: 40px;
    text-align: center;
  }

  .col-actions {
    width: 120px;
    text-align: right;
  }

  .action-buttons {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 0.5rem;
  }

  /* States */
  .table-loading,
  .table-error,
  .table-empty {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 3rem 1rem;
    color: #6b7280;
  }

  .table-loading :global(svg.spin) {
    animation: spin 1s linear infinite;
  }

  @keyframes spin {
    from {
      transform: rotate(0deg);
    }
    to {
      transform: rotate(360deg);
    }
  }

  /* Pagination */
  .table-pagination {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 1rem;
    border-top: 1px solid #e5e7eb;
  }

  .pagination-info {
    font-size: 0.875rem;
    color: #6b7280;
  }

  .pagination-controls {
    display: flex;
    align-items: center;
    gap: 0.5rem;
  }

  .page-indicator {
    font-size: 0.875rem;
    color: #374151;
    margin: 0 0.5rem;
  }

  /* Buttons */
  .btn {
    padding: 0.5rem 1rem;
    border-radius: 4px;
    font-size: 0.875rem;
    font-weight: 500;
    cursor: pointer;
    border: 1px solid transparent;
    transition: all 0.2s;
  }

  .btn-sm {
    padding: 0.375rem 0.75rem;
    font-size: 0.8125rem;
  }

  .btn-icon {
    padding: 0.5rem;
    background: none;
    border: none;
    cursor: pointer;
    color: #6b7280;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 4px;
    transition: all 0.2s;
  }

  .btn-icon:hover:not(:disabled) {
    background: #f3f4f6;
    color: #374151;
  }

  .btn-icon:disabled {
    opacity: 0.5;
    cursor: not-allowed;
  }

  .btn-secondary {
    background: white;
    color: #374151;
    border-color: #d1d5db;
  }

  .btn-secondary:hover {
    background: #f9fafb;
    border-color: #9ca3af;
  }

  .btn-danger {
    background: #ef4444;
    color: white;
  }

  .btn-danger:hover {
    background: #dc2626;
  }

  /* Responsive */
  @media (max-width: 768px) {
    .table-toolbar {
      flex-direction: column;
      align-items: stretch;
    }

    .toolbar-left,
    .toolbar-right {
      width: 100%;
    }

    .search-box {
      min-width: auto;
    }

    .table-pagination {
      flex-direction: column;
      gap: 1rem;
    }
  }
</style>
